package com.mazaiting.rtda.heap;

import com.mazaiting.classfile.attr.MemberInfo;
import lombok.Getter;
import lombok.Setter;

import java.util.Objects;

/**
 * 字段和方法都属于类的成员，它们有一些相同的信息（访问标 志、名字、描述符）
 *
 * @author mazaiting
 * @since 2021/8/16
 */
@Setter
@Getter
public class MtClassMember {
    /**
     * 访问修饰符
     */
    protected short accessFlags;
    /**
     * 名称
     */
    protected String name;
    /**
     * 描述
     */
    protected String descriptor;
    /**
     * 类
     * class字段存放Class结构体指针，这样可以通过字段或方法访问到它所属的类
     */
    protected MtClass mtClass;

    /**
     * 拷贝成员信息
     *
     * @param info 成员信息
     */
    public void copyMemberInfo(MemberInfo info) {
        this.accessFlags = info.getAccessFlags();
        this.name = info.name();
        this.descriptor = info.descriptor();
    }

    /**
     * 判断是否为公共
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isPublic() {
        return MtAccessFlags.isPublic(accessFlags);
    }

    /**
     * 判断是否为被保护的
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isProtected() {
        return MtAccessFlags.isProtected(accessFlags);
    }

    /**
     * 判断是否为私有的
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isPrivate() {
        return MtAccessFlags.isPrivate(accessFlags);
    }

    /**
     * 判断是否为final
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isFinal() {
        return MtAccessFlags.isFinal(accessFlags);
    }

    /**
     * 判断是否为静态
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isStatic() {
        return MtAccessFlags.isStatic(accessFlags);
    }

    /**
     * 判断是否为Synthetic
     *
     * @return true: 包含; false: 不包含
     */
    public boolean isSynthetic() {
        return MtAccessFlags.isSynthetic(accessFlags);
    }

    /**
     * 判断是否有访问权限
     * 如果字段是public，则任何 类都可以访问。如果字段是protected，则只有子类和同一个包下的类可以访问。
     * 如果字段有默认访问权限（非public，非protected，也非privated），则只有同一个包下的类可以访问。
     * 否则，字段是 private，只有声明这个字段的类才能访问
     * @param tmpMtClass 类实例
     * @return true: 包含; false: 不包含
     */
    public boolean isAccessibleTo(MtClass tmpMtClass) {
        if (isPublic()) {
            return true;
        }
        if (isProtected()) {
            return Objects.equals(mtClass, tmpMtClass)  || tmpMtClass.isSubClassOf(mtClass)
                    || Objects.equals(mtClass.getPackageName(), tmpMtClass.getPackageName());
        }
        if (!isPrivate()) {
            return Objects.equals(mtClass.getPackageName(), tmpMtClass.getPackageName());
        }
        return Objects.equals(mtClass, tmpMtClass);
    }

}



















